package com.lb.activity.service.impl;

import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lb.activity.mapper.ExamineFlowStepMapper;
import com.lb.activity.mapper.ExamineRolePermissionMapper;
import com.lb.activity.mapper.LeaveBillMapper;
import com.lb.activity.po.ExamineFlowStep;
import com.lb.activity.po.ExamineRolePermission;
import com.lb.activity.po.LeaveBill;
import com.lb.activity.po.User;
import com.lb.activity.service.LeaveBillService;
import com.lb.activity.util.ResultUtil;
import com.lb.activity.util.SessionUtil;
import com.lb.activity.util.SnowflakeIdWorker;
import com.lb.activity.util.emumdata.CurrentStepEnum;
import com.lb.activity.vo.LeaveBillVo;
import com.lb.activity.vo.LeaveBillVoRunningProcess;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author liubin
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class LeaveBillServiceImpl implements LeaveBillService {

    @Autowired
    private SnowflakeIdWorker idWorker;

    @Autowired
    private LeaveBillMapper leaveBillMapper;

    @Autowired
    private ExamineRolePermissionMapper examineRolePermissionMapper;

    @Autowired
    private ExamineFlowStepMapper examineFlowStepMapper;

    @Autowired
    private IdentityService identityservice;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;


    @Override
    public ResultUtil addLeaveBillI(LeaveBillVo leaveBillVo) {
        User sessionUser = SessionUtil.getSessionUser();
        if(sessionUser != null){
            LeaveBill leaveBill = new LeaveBill();
            // 取ID
            long id = idWorker.nextId();
            BeanUtils.copyProperties(leaveBillVo,leaveBill);
            leaveBill.setLeaveId(id);
            String[] split = leaveBillVo.getApplyTimeStr().split(" - ");
            leaveBill.setStartDate(DateUtil.parse(split[0]));
            leaveBill.setEndDate(DateUtil.parse(split[1]));
            leaveBill.setApplyDate(DateUtil.date(System.currentTimeMillis()));
            leaveBill.setProposer(sessionUser.getUserNameCn());
            leaveBill.setProposerId(sessionUser.getId());
            leaveBill.setCurrentStep(CurrentStepEnum.DEPT_LEADER.getCurrentStep());
            leaveBillMapper.insertSelective(leaveBill);
            //开始流程
            //使用leaveapply表的主键作为businesskey,连接业务数据和流程数据
            String businesskey=String.valueOf(id);
            identityservice.setAuthenticatedUserId(sessionUser.getId()+"");
            Map<String, Object> variables = new HashMap<String, Object>();
            variables.put("applyuserid", sessionUser.getId()+"");
            ProcessInstance instance=runtimeService.startProcessInstanceByKey("leave",businesskey,variables);
            String instanceid=instance.getId();
            leaveBill.setProcessInstanceId(instanceid);
            ExamineFlowStep step = ExamineFlowStep.builder()
                    .id(idWorker.nextId())
                    .workId(id)
                    .stepUser(sessionUser.getUserNameCn())
                    .stepUserId(sessionUser.getId())
                    .stepName("申请")
                    .stepSuggest("同意")
                    .build();
            leaveBillMapper.updateByPrimaryKeySelective(leaveBill);
            examineFlowStepMapper.insertSelective(step);
            return ResultUtil.ok();
        }else{
            return ResultUtil.build(400,"请重新登录系统");
        }

    }

    @Override
    public ResultUtil myLeaveBillList(LeaveBillVo leaveBillVo) {
        Integer limit = leaveBillVo.getLimit();
        Integer page = leaveBillVo.getPage()-1;
        String userid =  SessionUtil.getSessionUser().getId()+"";
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();
        ProcessInstanceQuery leave = query.processDefinitionKey("leave").involvedUser(userid);
        int total = Integer.parseInt(leave.count()+"");
        List<ProcessInstance> leaves = leave.listPage(page, limit);
        List<LeaveBillVoRunningProcess> list = new ArrayList<>();
        for (ProcessInstance p : leaves) {
            LeaveBillVoRunningProcess process = new LeaveBillVoRunningProcess();
            // 查询
            LeaveBill leaveBill = leaveBillMapper.selectByPrimaryKey(Long.parseLong(p.getBusinessKey()));
            BeanUtils.copyProperties(leaveBill,process);
            process.setActivityid(p.getActivityId());
            process.setBusinesskey(p.getBusinessKey());
            process.setExecutionid(p.getId());
            process.setProcessInstanceId(p.getProcessInstanceId());
            process.setApplyDateStr(DateUtil.formatDate(leaveBill.getApplyDate()));
            process.setStartDateStr(DateUtil.formatDate(leaveBill.getStartDate()));
            process.setEndDateStr(DateUtil.formatDate(leaveBill.getEndDate()));
            if (leaveBill.getProposerId().equals(Long.parseLong(userid))) {
                list.add(process);
            }else {
                continue;
            }
        }
        return ResultUtil.build(0, "", total, list);
    }

    @Override
    public List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity, List<HistoricActivityInstance> historicActivityInstances) {
        // 用以保存高亮的线flowId
        List<String> highFlows = new ArrayList<String>();
        // 对历史流程节点进行遍历
        for (int i = 0; i < historicActivityInstances.size(); i++) {
            // 得 到节点定义的详细信息
            ActivityImpl activityImpl = processDefinitionEntity.findActivity(historicActivityInstances.get(i).getActivityId());
            // 用以保存后需开始时间相同的节点
            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();
            if ((i + 1) >= historicActivityInstances.size()) {
                break;
            }
            // 将后面第一个节点放在时间相同节点的集合里
            ActivityImpl sameActivityImpl1 = processDefinitionEntity.findActivity(historicActivityInstances.get(i + 1).getActivityId());
            sameStartTimeNodes.add(sameActivityImpl1);
            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
                // 后续第一个节点
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);
                // 后续第二个节点
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);
                // 如果第一个节点和第二个节点开始时间相同保存
                if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {
                    ActivityImpl sameActivityImpl2 = processDefinitionEntity.findActivity(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                } else {
                    // 有不相同跳出循环
                    break;
                }
            }
            // 取出节点的所有出去的线
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();
            // 对所有的线进行遍历
            for (PvmTransition pvmTransition : pvmTransitions) {
                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }
        }
        return highFlows;
    }

    /**
     * 1 判断有没有 审批权限 分为无审批角色  或者 无审批权限
     * 2 拿取所在的部门下的申请记录
     * @param leaveBillVo
     * @return
     */
    @Override
    public ResultUtil deptLeaveBillList(LeaveBillVo leaveBillVo) {
        // 拿取userId
        User sessionUser =  SessionUtil.getSessionUser();
        if(sessionUser.getExamineRole() != null){
            //查询审批权限，是否有部门审批权限
            ExamineRolePermission permissions = examineRolePermissionMapper.selectPermissionsByRoleIdAndCode(sessionUser.getExamineRole(),"dept");
            if(permissions != null) {
                // 拥有权限
                //查询所有待办任务
                List<LeaveBillVoRunningProcess> results = new ArrayList<LeaveBillVoRunningProcess>();
                List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("部门经理").listPage(leaveBillVo.getPage() - 1, leaveBillVo.getLimit());
                for (Task task : tasks) {
                    String instanceid = task.getProcessInstanceId();
                    ProcessInstance ins = runtimeService.createProcessInstanceQuery().processInstanceId(instanceid).singleResult();
                    String businesskey = ins.getBusinessKey();

                    LeaveBill leaveBill = leaveBillMapper.selectByPrimaryKey(Long.parseLong(businesskey));
                    LeaveBillVoRunningProcess process = new LeaveBillVoRunningProcess();
                    if (leaveBill.getDeptId().equals(sessionUser.getGroupId())) {
                        BeanUtils.copyProperties(leaveBill, process);
                        process.setApplyDateStr(DateUtil.formatDate(leaveBill.getApplyDate()));
                        process.setStartDateStr(DateUtil.formatDate(leaveBill.getStartDate()));
                        process.setEndDateStr(DateUtil.formatDate(leaveBill.getEndDate()));
                        // 赋值
                        process.setTaskId(task.getId());
                        process.setProcessInstanceId(task.getProcessInstanceId());
                        process.setTaskName(task.getName());
                        process.setProcessdefId(task.getProcessDefinitionId());
                        process.setTaskCreateTime(task.getCreateTime());
                        results.add(process);
                    }
                }
                return ResultUtil.build(0,"",taskService.createTaskQuery().taskCandidateGroup("部门经理").list().size(),results);
            }else{
                return null;
            }
        }

        return null;
    }

    @Override
    public LeaveBill getOneLeaveBill(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId())
                .singleResult();
        return leaveBillMapper.selectByPrimaryKey(Long.parseLong(process.getBusinessKey()));
    }

    @Override
    public ResultUtil complateLeaveBill(String taskId, String approve) {
        User sessionUser = SessionUtil.getSessionUser();
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("deptleaderapprove", approve);
        LeaveBill oneLeaveBill = getOneLeaveBill(taskId);
        if("true".equals(approve)){
            oneLeaveBill.setCurrentStep(CurrentStepEnum.HUMAN_LEADER.getCurrentStep());
            ExamineFlowStep step = ExamineFlowStep.builder()
                    .id(idWorker.nextId())
                    .workId(oneLeaveBill.getLeaveId())
                    .stepUser(sessionUser.getUserNameCn())
                    .stepUserId(sessionUser.getId())
                    .stepName("部门领导")
                    .stepSuggest("同意")
                    .build();
            examineFlowStepMapper.insertSelective(step);
        }else{
            ExamineFlowStep step = ExamineFlowStep.builder()
                    .id(idWorker.nextId())
                    .workId(oneLeaveBill.getLeaveId())
                    .stepUser(sessionUser.getUserNameCn())
                    .stepUserId(sessionUser.getId())
                    .stepName("部门领导")
                    .stepSuggest("拒绝")
                    .build();
            examineFlowStepMapper.insertSelective(step);
            oneLeaveBill.setCurrentStep(CurrentStepEnum.APPLY_AGAIN.getCurrentStep());
        }
        leaveBillMapper.updateByPrimaryKeySelective(oneLeaveBill);
        taskService.claim(taskId, sessionUser.getId()+"");
        taskService.complete(taskId, variables);
        return ResultUtil.ok();
    }



    @Override
    public ResultUtil deptLeaveBillPersonList(LeaveBillVo leaveBillVo) {

        // 拿取userId
        User sessionUser =  SessionUtil.getSessionUser();
        if(sessionUser.getExamineRole() != null){
            //查询审批权限，是否有 人力审批权限
            ExamineRolePermission permissions = examineRolePermissionMapper.selectPermissionsByRoleIdAndCode(sessionUser.getExamineRole(),"renli");
            if(permissions != null) {
                // 拥有权限
                //查询所有待办任务
                List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("人事").listPage(leaveBillVo.getPage() - 1, leaveBillVo.getLimit());
                List<LeaveBillVoRunningProcess> results = formatData(tasks);
                return ResultUtil.build(0,"",taskService.createTaskQuery().taskCandidateGroup("人事").list().size(),results);
            }else{
                return null;
            }
        }

        return null;
    }

    @Override
    public ResultUtil complateHrLeaveBill(String taskId, String hrapprove) {
        User sessionUser = SessionUtil.getSessionUser();
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("hrapprove", hrapprove);
        LeaveBill oneLeaveBill = getOneLeaveBill(taskId);
        if("true".equals(hrapprove)){
            ExamineFlowStep step = ExamineFlowStep.builder()
                    .id(idWorker.nextId())
                    .workId(oneLeaveBill.getLeaveId())
                    .stepUser(sessionUser.getUserNameCn())
                    .stepUserId(sessionUser.getId())
                    .stepName("人力资源")
                    .stepSuggest("同意")
                    .build();
            examineFlowStepMapper.insertSelective(step);
            oneLeaveBill.setCurrentStep(CurrentStepEnum.REPORT_BACK.getCurrentStep());
        }else{
            ExamineFlowStep step = ExamineFlowStep.builder()
                    .id(idWorker.nextId())
                    .workId(oneLeaveBill.getLeaveId())
                    .stepUser(sessionUser.getUserNameCn())
                    .stepUserId(sessionUser.getId())
                    .stepName("人力资源")
                    .stepSuggest("拒绝")
                    .build();
            examineFlowStepMapper.insertSelective(step);
            oneLeaveBill.setCurrentStep(CurrentStepEnum.APPLY_AGAIN.getCurrentStep());
        }
        leaveBillMapper.updateByPrimaryKeySelective(oneLeaveBill);
        taskService.claim(taskId, sessionUser.getId()+"");
        taskService.complete(taskId, variables);
        return ResultUtil.ok();
    }

    @Override
    public ResultUtil myLeaveBillReportBackList(LeaveBillVo leaveBillVo) {
        User sessionUser =  SessionUtil.getSessionUser();
        if(sessionUser != null) {
            List<Task> tasks = taskService.createTaskQuery().taskCandidateOrAssigned(sessionUser.getId()+"").taskName("销假").listPage(leaveBillVo.getPage() - 1, leaveBillVo.getLimit());
            List<LeaveBillVoRunningProcess> results = formatData(tasks);
            return ResultUtil.build(0, "", taskService.createTaskQuery().taskCandidateOrAssigned(sessionUser.getId()+"").taskName("销假").list().size(), results);
        }else{
            return null;
        }
    }

    @Override
    public ResultUtil editMyLeaveBillReportBack(LeaveBillVo leaveBillVo) {
        User sessionUser = SessionUtil.getSessionUser();
        Task task = taskService.createTaskQuery().taskId(leaveBillVo.getTaskId()).singleResult();
        ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId())
                .singleResult();
        LeaveBill leaveBill = LeaveBill.builder()
                .leaveId(Long.parseLong(process.getBusinessKey()))
                .reportStartTime(DateUtil.parse(leaveBillVo.getReportStartTimeStr()))
                .reportEndTime(DateUtil.parse(leaveBillVo.getReportEndTimeStr()))
                .currentStep(CurrentStepEnum.END.getCurrentStep())
                .build();
        leaveBillMapper.updateByPrimaryKeySelective(leaveBill);
        ExamineFlowStep step = ExamineFlowStep.builder()
                .id(idWorker.nextId())
                .workId(leaveBill.getLeaveId())
                .stepUser(sessionUser.getUserNameCn())
                .stepUserId(sessionUser.getId())
                .stepName("申请人销假")
                .stepSuggest("已销假")
                .build();
        examineFlowStepMapper.insertSelective(step);
        taskService.complete(leaveBillVo.getTaskId());
        return ResultUtil.ok();
    }

    /**
     * 调整申请
     * @param leaveBillVo
     * @return
     */
    @Override
    public ResultUtil myLeaveBillApplyAgainList(LeaveBillVo leaveBillVo) {
        User sessionUser =  SessionUtil.getSessionUser();
        if(sessionUser != null) {
            List<Task> tasks = taskService.createTaskQuery().taskCandidateOrAssigned(sessionUser.getId()+"").taskName("调整申请").listPage(leaveBillVo.getPage() - 1, leaveBillVo.getLimit());
            List<LeaveBillVoRunningProcess> results = formatData(tasks);
            return ResultUtil.build(0, "", taskService.createTaskQuery().taskCandidateOrAssigned(sessionUser.getId()+"").taskName("调整申请").list().size(), results);
        }else{
            return null;
        }
    }

    @Override
    public ResultUtil editMyLeaveBillApplyAgain(LeaveBillVo leaveBillVo) {
        User sessionUser =  SessionUtil.getSessionUser();
        Map<String,Object> variables=new HashMap<String,Object>();
        variables.put("reapply", leaveBillVo.getReapply());
        Task task = taskService.createTaskQuery().taskId(leaveBillVo.getTaskId()).singleResult();
        ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId())
                .singleResult();
        if(leaveBillVo.getReapply().equals("true")){
            LeaveBill leaveBill = LeaveBill.builder()
                    .leaveId(Long.parseLong(process.getBusinessKey()))
                    .startDate(DateUtil.parse(leaveBillVo.getStartTimeStr()))
                    .endDate(DateUtil.parse(leaveBillVo.getEndTimeStr()))
                    .days(leaveBillVo.getDays())
                    .leaveType(leaveBillVo.getLeaveType())
                    .leaveReason(leaveBillVo.getLeaveReason())
                    .currentStep(CurrentStepEnum.DEPT_LEADER.getCurrentStep())
                    .build();
            leaveBillMapper.updateByPrimaryKeySelective(leaveBill);
            ExamineFlowStep step = ExamineFlowStep.builder()
                    .id(idWorker.nextId())
                    .workId(leaveBill.getLeaveId())
                    .stepUser(sessionUser.getUserNameCn())
                    .stepUserId(sessionUser.getId())
                    .stepName("申请人重新申请")
                    .stepSuggest("同意")
                    .build();
            examineFlowStepMapper.insertSelective(step);
        }else{
            ExamineFlowStep step = ExamineFlowStep.builder()
                    .id(idWorker.nextId())
                    .workId(Long.parseLong(process.getBusinessKey()))
                    .stepUser(sessionUser.getUserNameCn())
                    .stepUserId(sessionUser.getId())
                    .stepName("申请人取消申请")
                    .stepSuggest("取消申请，流程已结束")
                    .build();
            examineFlowStepMapper.insertSelective(step);
        }
        taskService.complete(leaveBillVo.getTaskId(),variables);
        return ResultUtil.ok();
    }

    @Override
    public ResultUtil myLeaveBillAll(LeaveBillVo leaveBillVo) {
        PageHelper.startPage(leaveBillVo.getPage(),leaveBillVo.getLimit());
        List<LeaveBill> leaveBills = leaveBillMapper.selectAll();
        PageInfo<LeaveBill> pageInfo = new PageInfo<>(leaveBills);
        return ResultUtil.build(0, "", Integer.parseInt(pageInfo.getTotal()+""), leaveBills);
    }

    @Override
    public List<ExamineFlowStep> getExamineStep(Long leaveId) {
        Example example = new Example(ExamineFlowStep.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("workId",leaveId);
        example.setOrderByClause(" create_time desc ");
        List<ExamineFlowStep> examineFlowSteps = examineFlowStepMapper.selectByExample(example);
        return examineFlowSteps;
    }

    /**
     * 格式化数据
     * @param tasks
     * @return
     */
    public List<LeaveBillVoRunningProcess> formatData(List<Task> tasks ){
        List<LeaveBillVoRunningProcess> results = new ArrayList<LeaveBillVoRunningProcess>();
        for (Task task : tasks) {
            String instanceid = task.getProcessInstanceId();
            ProcessInstance ins = runtimeService.createProcessInstanceQuery().processInstanceId(instanceid).singleResult();
            String businesskey = ins.getBusinessKey();

            LeaveBill leaveBill = leaveBillMapper.selectByPrimaryKey(Long.parseLong(businesskey));
            LeaveBillVoRunningProcess process = new LeaveBillVoRunningProcess();
            BeanUtils.copyProperties(leaveBill, process);
            process.setApplyDateStr(DateUtil.formatDate(leaveBill.getApplyDate()));
            process.setStartDateStr(DateUtil.formatDate(leaveBill.getStartDate()));
            process.setEndDateStr(DateUtil.formatDate(leaveBill.getEndDate()));
            // 赋值
            process.setTaskId(task.getId());
            process.setProcessInstanceId(task.getProcessInstanceId());
            process.setTaskName(task.getName());
            process.setProcessdefId(task.getProcessDefinitionId());
            process.setTaskCreateTime(task.getCreateTime());
            results.add(process);
        }
        return results;
    }



}
